﻿#include <math.h>
#include <ctime>
#include <Solar/SimulationTimer.h>
#define dnint(A) ((A)<0.0?ceil((A)-0.5):floor((A)+0.5))
CFxSimulationTimer* CFxSimulationTimer::s_pSimulationTimer = nullptr;
CFxSimulationTimer* CFxSimulationTimer::instance()
{
	if (!s_pSimulationTimer)
	{
		s_pSimulationTimer = new CFxSimulationTimer;
	}
	return s_pSimulationTimer;
}

void CFxSimulationTimer::unstance()
{
	if (s_pSimulationTimer)
	{
		delete s_pSimulationTimer;
		s_pSimulationTimer = nullptr;
	}
}

CFxSimulationTimer::CFxSimulationTimer()
	:m_bTick(false)
	,m_dTimeBegin(10.0)
	,m_dTimeCurrent(0.0)
	,m_dTimeCurrentFrame(0.0)
	,m_dTimeRatio(1.0)
	,m_dDirection(1.0)
	,m_dTimeTick(10.0)
{
	connect(&m_timerTick, SIGNAL(timeoutSignal(double)), this, SLOT(tickSlot(double)));
	m_timerTick.start(m_dTimeTick);

	// 初始化时间
	time_t tt = time(NULL);
	tm tmLocal = *localtime(&tt);
	double dJDutc = calToJD(tmLocal.tm_year+1900
		,tmLocal.tm_mon+1,tmLocal.tm_mday,tmLocal.tm_hour - 8.0,tmLocal.tm_min,tmLocal.tm_sec);
	setTimeBegin(dJDutc);
	setTimeCurrent(dJDutc);
	start();
}

CFxSimulationTimer::~CFxSimulationTimer()
{

}


void CFxSimulationTimer::start()
{
	m_bTick = true;
}

void CFxSimulationTimer::stop()
{
	m_bTick = false;
	m_dTimeCurrent = m_dTimeBegin;
	m_dTimeCurrentFrame = m_dTimeBegin;
	m_dTimeRatio = 1.0;
	m_dDirection = 1.0;
	m_dTimeTick = 10.0;
}

void CFxSimulationTimer::pause()
{
	m_bTick = false;
}

void CFxSimulationTimer::reverse()
{
	m_dDirection *= -1.0;
}

void CFxSimulationTimer::tick(double dSec)
{
	if(m_bTick==false) 
		return;
	m_dTimeCurrent += (dSec/86400.0 * m_dTimeRatio * m_dDirection);//当前的仿真时间
}

void CFxSimulationTimer::enableClockTimer( bool bTick )
{
	if (bTick)
	{
		m_timerTick.start(m_dTimeTick);
	}
	else
	{
		m_timerTick.stop();
	}	
}


void CFxSimulationTimer::tickSlot(double dTime)
{
	tick(dTime);
}

/**  
* @brief 格里高利历转儒略日
* @param nYear [in] 年
* @param nMonth [in] 月
* @param nDay [in] 日
* @param nHour [in] 时
* @param nMin [in] 分
* @param dSec [in] 秒
* @return 儒略日日期
*/
double calToJD(int nYear, int nMonth, int nDay, int nHour, int nMin, double dSec)
{
	double dJMJD0 = 2400000.5;

	long iypmy;

	static const int mtab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

	int nLy = ((nMonth == 2) && !(nYear%4) && (nYear%100 || !(nYear%400)));

	int nMy = (nMonth - 14) / 12;
	iypmy = (long) (nYear + nMy);
	double dDate = (double)((1461L * (iypmy + 4800L)) / 4L
		+ (367L * (long) (nMonth - 2 - 12 * nMy)) / 12L
		- (3L * ((iypmy + 4900L) / 100L)) / 4L
		+ (long) nDay - 2432076L);

	double dTime = ( 60.0*(double)(60*nHour + nMin) + dSec ) / 86400.0;
	double dUTC = dDate + dTime;
	return dJMJD0+dUTC;
}

/**  
* @brief 儒略日转格里高利历
* @param dJD [in] 儒略日日期
* @param nYear [out] 年
* @param nMonth [out] 月
* @param nDay [out] 日
* @param nHour [out] 时
* @param nMin [out] 分
* @param dSec [out] 秒
*/
void jdToCal(double dJD, int& nYear, int& nMonth, int& nDay,int& nHour, int& nMin, double& dSec)
{
	long jd, l, n, i, k;
	double dj, d1, d2, f1, f2, d;

	dj = dJD ;

	d1 = dJD;
	d2 = -0.5;

	f1 = fmod(d1, 1.0);
	f2 = fmod(d2, 1.0);
	double dDay = fmod(f1 + f2, 1.0);
	if (dDay < 0.0) dDay += 1.0;
	d = dnint(d1-f1) + dnint(d2-f2) + dnint(f1+f2-dDay);
	jd = (long) dnint(d) + 1L;

	l = jd + 68569L;
	n = (4L * l) / 146097L;
	l -= (146097L * n + 3L) / 4L;
	i = (4000L * (l + 1L)) / 1461001L;
	l -= (1461L * i) / 4L - 31L;
	k = (80L * l) / 2447L;
	nDay = (int) (l - (2447L * k) / 80L);
	l = k / 11L;
	nMonth = (int) (k + 2L - 12L * l);
	nYear = (int) (100L * (n - 49L) + i + l);

	double dHour = dDay*24.0;
	nHour = int(dHour);
	double dMin = (dHour - nHour)*60.0;
	nMin = int(dMin);
	dSec  = (dMin - nMin)*60.0;
}
